#include "stdafx.h"
#include "libraries.h"

#include "Application.h"
#include "Filesystem.h"

using namespace Cvekas;

class SpriteDemo : public Application
{
public:
	SpriteDemo(HINSTANCE instance, const std::string& name, const std::string& log_filename)
		:
	Application(instance, name, log_filename)
	{
		Filesystem::init();
	}

	virtual ~SpriteDemo() {}

	virtual void initVideoDevice()
	{
		settings->insert("video", VideoSettings());

		(*settings)["video"]["ScreenWidth"] = 800;
		(*settings)["video"]["ScreenHeight"] = 600;
		(*settings)["video"]["VSync"] = false;
		(*settings)["video"]["Fullscreen"] = false;

		window = WindowPtr(new Window(instance, name));
		video_device->init(window);
	}

	virtual void init()
	{
		sprite_batch = video_device->createSpriteBatch(main_renderer, 800, 600, 1000);

		// Load textures
		tex_balls = video_device->getTextureManager()->loadTexture2D("balls", Filesystem::redirect("balls.png"));
		tex_blocks = video_device->getTextureManager()->loadTexture2D("blocks", Filesystem::redirect("blocks.png"));

		// Generate texture source rectangles
		for(int i = 0; i < 7; ++i)
			src_balls[i] = RectF(64.0f * float(i), 0.0f, 64.0f, 64.0f);

		for(int i = 0; i < 8; ++i)
			src_blocks[i] = RectF(32.0f * float(i % 4), 32.0f * float(i / 4), 32.0f, 32.0f);

		// Initialize ball positions and velocities
		srand(0);
		for(int i = 0; i < n_balls; ++i)
		{
			int x = rand()%(800-64);
			int y = rand()%(600-64);
			
			pos_balls[i] = Vector2(float(x), float(y));
			vel_balls[i] = Vector2(float(x - 400), float(y - 300)).getNormalized();
		}
	}

	virtual bool update()
	{
		// Update balls
		for(int i = 0; i < n_balls; ++i)
		{
			pos_balls[i] += vel_balls[i] * (Timer::getTimeScale()*100.0f);

			if(pos_balls[i].x < 0.0f || pos_balls[i].x > (800.0-64.0))
				vel_balls[i].x *= -1;

			if(pos_balls[i].y < 0.0f || pos_balls[i].y > (600.0-64.0))
				vel_balls[i].y *= -1;
		}

		return true;
	}

	virtual bool render()
	{
		video_device->beginScene();

		int offset = (Timer::getTimeMs() / 20) % 32;

		// Fill background with rectangles
		for(int y = 0; y < 20; ++y)
			for(int x = 0; x < 26; ++x)
				sprite_batch->draw(tex_blocks, 0, src_blocks[(x+(19-y))&7], 
				Vector2(32.0f * float(x) - float(offset), 32.0f * float(y) - float(offset)));

		// Draw balls
		for(int i = 0; i < n_balls; ++i)
			sprite_batch->draw(tex_balls, 1, src_balls[i%7], pos_balls[i], Color(255, 255, 255, 128));
		
		sprite_batch->present();

		main_renderer->render();

		video_device->endScene();	

		main_renderer->endFrame();

		return true;
	}

private:
	static const uint n_balls = 1000;

	SpriteBatchPtr sprite_batch;

	Texture2DPtr tex_balls;
	Texture2DPtr tex_blocks;

	RectF src_balls[7];
	RectF src_blocks[8];

	Vector2 vel_balls[n_balls];
	Vector2 pos_balls[n_balls];
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
	SpriteDemo demo(hInstance, "Sprites Demo", "SpritesDemo.log");
	try
	{
		demo.run();
	}
	catch (std::exception& e)
	{
		MessageBox(NULL, e.what(), "Fatal error", NULL);
	}
	return 0;
}